package com.xingyang.yutnori.ui;

import com.xingyang.yutnori.model.*;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.*;
import java.util.List;
import javax.swing.border.EmptyBorder;

/**
 * A panel that displays and animates the Yut sticks.
 * Allows the player to throw the sticks and see the result.
 */
public class YutStickPanel extends JPanel {
    
    // Constants for the panel
    private static final int PANEL_WIDTH = 330;
    private static final int PANEL_HEIGHT = 400;
    
    // Constants for the yut sticks
    private static final int STICK_LENGTH = 120;
    private static final int STICK_WIDTH = 25;
    private static final int STICK_SPACING = 15;
    private static final int STICK_CURVE = 10;
    
    // Colors for the sticks
    private static final Color STICK_FRONT_COLOR = new Color(235, 225, 205);
    private static final Color STICK_BACK_COLOR = new Color(120, 80, 40);
    private static final Color STICK_EDGE_COLOR = new Color(160, 120, 80);
    private static final Color HIGHLIGHT_COLOR = new Color(255, 220, 100);
    
    // Animation properties
    private javax.swing.Timer animationTimer;
    private int animationStep;
    private static final int TOTAL_ANIMATION_STEPS = 30; // Increase animation steps for smoother animation
    private boolean[] stickSides; // true = front (flat), false = back (rounded)
    private int[] stickRotations; // Rotation angles during animation
    private int[] stickPositionsX; // X positions during animation
    private int[] stickPositionsY; // Y positions during animation
    private boolean animating = false;
    
    // Reference to the game
    private Game game;
    private GameBoard gameBoard;
    
    // UI components
    private JButton throwButton;
    private JLabel resultLabel;
    
    // Listeners
    private List<YutThrowListener> throwListeners;
    
    // Random generator for animation
    private Random random = new Random();

    // For traditional mat background
    private Color matColor = new Color(210, 180, 140);
    private Color matLineColor = new Color(180, 150, 100, 80);
    
    // Add a static Random instance for better randomization
    private static final Random RANDOM = new Random();
    
    /**
     * Constructs a new YutStickPanel.
     * 
     * @param gameBoard The game board to update after throws
     */
    public YutStickPanel(GameBoard gameBoard) {
        this.gameBoard = gameBoard;
        this.game = gameBoard.getGame();
        
        initializePanel();
        createComponents();
        setupEventListeners();
        setupAnimation();
        
        throwListeners = new ArrayList<>();
        stickSides = new boolean[4];
        stickRotations = new int[4];
        stickPositionsX = new int[4];
        stickPositionsY = new int[4];
        
        // Initialize the sticks to show front sides
        resetSticks();
    }
    
    /**
     * Interface to listen for yut throw events.
     */
    public interface YutThrowListener {
        void onYutThrown(int result);
    }
    
    /**
     * Adds a listener for yut throw events.
     * 
     * @param listener The listener to add
     */
    public void addYutThrowListener(YutThrowListener listener) {
        throwListeners.add(listener);
    }
    
    /**
     * Sets the game reference.
     * 
     * @param game The game to reference
     */
    public void setGame(Game game) {
        this.game = game;
    }
    
    /**
     * Initializes the panel properties.
     */
    private void initializePanel() {
        setPreferredSize(new Dimension(PANEL_WIDTH, PANEL_HEIGHT));
        setMinimumSize(new Dimension(PANEL_WIDTH, PANEL_HEIGHT));
        setMaximumSize(new Dimension(PANEL_WIDTH, PANEL_HEIGHT));
        setBackground(new Color(245, 240, 220));
        setBorder(BorderFactory.createCompoundBorder(
            BorderFactory.createLineBorder(new Color(139, 69, 19), 2),
            BorderFactory.createEmptyBorder(10, 10, 10, 10)
        ));
        setLayout(new BorderLayout(0, 10));
        setOpaque(true);
    }
    
    /**
     * Creates UI components for the panel.
     */
    private void createComponents() {
        // Create a prominent panel title with wooden background
        JPanel titlePanel = new JPanel();
        titlePanel.setOpaque(false);
        titlePanel.setLayout(new BorderLayout());
        
        JLabel titleLabel = new JLabel("Yut Sticks", JLabel.CENTER);
        titleLabel.setFont(new Font("SansSerif", Font.BOLD, 20));
        titleLabel.setForeground(new Color(110, 60, 10));
        titlePanel.add(titleLabel, BorderLayout.CENTER);
        
        // Create the result label
        resultLabel = new JLabel("Ready!", JLabel.CENTER);
        resultLabel.setFont(new Font("SansSerif", Font.BOLD, 18));
        resultLabel.setForeground(new Color(139, 69, 19));
        
        // Create the throw button with English text and wood-like styling
        throwButton = new JButton("Throw Yut");
        throwButton.setFont(new Font("SansSerif", Font.BOLD, 16));
        throwButton.setBackground(new Color(70, 130, 180));
        throwButton.setForeground(Color.WHITE);
        throwButton.setFocusPainted(false);
        throwButton.setBorder(BorderFactory.createCompoundBorder(
            BorderFactory.createLineBorder(new Color(30, 70, 120), 2),
            BorderFactory.createEmptyBorder(10, 15, 10, 15)
        ));
        
        // Add hover effect
        throwButton.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseEntered(MouseEvent e) {
                if (throwButton.isEnabled()) {
                    throwButton.setBackground(new Color(100, 160, 210));
                    setCursor(new Cursor(Cursor.HAND_CURSOR));
                }
            }
            
            @Override
            public void mouseExited(MouseEvent e) {
                if (throwButton.isEnabled()) {
                    throwButton.setBackground(new Color(70, 130, 180));
                    setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
                }
            }
        });
        
        // Create a styled panel for the controls (bottom part)
        JPanel controlPanel = new JPanel();
        controlPanel.setLayout(new BorderLayout(0, 5));
        controlPanel.setOpaque(false);
        controlPanel.add(resultLabel, BorderLayout.NORTH);
        controlPanel.add(throwButton, BorderLayout.CENTER);
        
        // Add the components to their positions
        add(titlePanel, BorderLayout.NORTH);
        add(Box.createVerticalGlue(), BorderLayout.CENTER); // Space for sticks
        add(controlPanel, BorderLayout.SOUTH);
    }
    
    /**
     * Sets up event listeners for the panel.
     */
    private void setupEventListeners() {
        throwButton.addActionListener(e -> {
            throwYutSticks();
        });
    }
    
    /**
     * Sets up the animation timer.
     */
    private void setupAnimation() {
        animationTimer = new javax.swing.Timer(35, e -> {
            animationStep++;
            
            // Update stick animations
            for (int i = 0; i < 4; i++) {
                // Calculate rotation based on animation progress
                if (animationStep < TOTAL_ANIMATION_STEPS * 0.7) {
                    // During the first 70% of animation, sticks are spinning and moving
                    stickRotations[i] = (stickRotations[i] + 10 + random.nextInt(15)) % 360;
                    
                    // Add some random movement to each stick
                    stickPositionsX[i] += random.nextInt(21) - 10;
                    stickPositionsY[i] += random.nextInt(11) - 5;
                    
                    // Keep sticks within view
                    stickPositionsX[i] = Math.max(20, Math.min(PANEL_WIDTH - 20 - STICK_LENGTH, stickPositionsX[i]));
                    stickPositionsY[i] = Math.max(50, Math.min(PANEL_HEIGHT - 150, stickPositionsY[i]));
                }
                // We don't randomize stick sides here anymore, as determineResult handles it
            }
            
            if (animationStep >= TOTAL_ANIMATION_STEPS) {
                // Animation complete
                animationTimer.stop();
                animating = false;
                throwButton.setEnabled(true);
                
                // Determine the throw result - this will also set the appropriate stick sides
                int result = determineResult();
                
                // Update the result label
                updateResultLabel(result);
                
                // Position sticks neatly in their final state
                arrangeSticks();
                
                // Notify listeners of the throw result
                for (YutThrowListener listener : throwListeners) {
                    listener.onYutThrown(result);
                }
            }
            
            repaint();
        });
    }
    
    /**
     * Randomly decides if we should show BackDo
     * This helps ensure BackDo appears sometimes
     */
    private boolean needsBackDo() {
        // No longer needed as BackDo is handled in determineResult()
        return false;
    }
    
    /**
     * Throws the yut sticks and performs the animation.
     */
    private void throwYutSticks() {
        // Prevent multiple throws during animation
        if (animating) {
            return;
        }
        
        // If player has available rolls, they must use them first
        if (!game.getAvailableRolls().isEmpty()) {
            resultLabel.setText("Use your current roll(s) first!");
            return;
        }
        
        // If player has already rolled and is not allowed to rethrow
        if (game.hasRolled()) {
            if (!game.isReThrowAllowed()) {
                resultLabel.setText("Click 'End Turn' to finish your turn");
                return;
            }
            // Reset hasRolled when using a rethrow
            game.setHasRolled(false);
        }
        
        animating = true;
        throwButton.setEnabled(false);
        
        // Set initial animation states
        for (int i = 0; i < 4; i++) {
            stickRotations[i] = RANDOM.nextInt(360);
            stickPositionsX[i] = PANEL_WIDTH/2 - STICK_LENGTH/2 + RANDOM.nextInt(40) - 20;
            stickPositionsY[i] = 80 + i * 30 + RANDOM.nextInt(20);
        }
        
        // Start the animation
        animationStep = 0;
        animationTimer.start();
        
        // Update result label to show that sticks are being thrown
        resultLabel.setText("Throwing...");
    }
    
    /**
     * Determines the result of the throw based on the sides of the sticks.
     * 
     * @return The result code (DO, GAE, GEOL, YUT, MO, or BACKDO)
     */
    private int determineResult() {
        // Use the shared Random instance and get a new value
        int randomValue = RANDOM.nextInt(100);
        
        // MO (5): 4个平面 - 15% chance
        if (randomValue < 15) {
            stickSides[0] = true;  // true = 平面
            stickSides[1] = true;
            stickSides[2] = true;
            stickSides[3] = true;
            return YutSet.MO;
        }
        // YUT (4): 4个圆面 - 15% chance
        else if (randomValue < 30) {
            stickSides[0] = false;  // false = 圆面
            stickSides[1] = false;
            stickSides[2] = false;
            stickSides[3] = false;
            return YutSet.YUT;
        }
        // GEOL (3): 1个平面，3个圆面 - 20% chance
        else if (randomValue < 50) {
            stickSides[0] = true;   // 1个平面
            stickSides[1] = false;  // 3个圆面
            stickSides[2] = false;
            stickSides[3] = false;
            return YutSet.GEOL;
        }
        // GAE (2): 2个平面，2个圆面 - 25% chance
        else if (randomValue < 75) {
            stickSides[0] = true;   // 2个平面
            stickSides[1] = true;
            stickSides[2] = false;  // 2个圆面
            stickSides[3] = false;
            return YutSet.GAE;
        }
        // DO (1): 3个平面，1个圆面 - 25% chance
        else {
            stickSides[0] = true;   // 3个平面
            stickSides[1] = true;
            stickSides[2] = true;
            stickSides[3] = false;  // 1个圆面
            return YutSet.DO;
        }
    }
    
    /**
     * Updates the result label based on the throw result.
     * 
     * @param result The throw result
     */
    private void updateResultLabel(int result) {
        // Determine the Korean and English names for the result
        String resultName = YutSet.getRollName(result);
        String resultColor = "";
        
        switch (result) {
            case YutSet.DO:
                resultName = "Do";
                resultColor = "#505050";
                break;
            case YutSet.GAE:
                resultName = "Gae";
                resultColor = "#0000A0";
                break;
            case YutSet.GEOL:
                resultName = "Geol";
                resultColor = "#006000";
                break;
            case YutSet.YUT:
                resultName = "Yut";
                resultColor = "#A00000";
                break;
            case YutSet.MO:
                resultName = "Mo";
                resultColor = "#C06000";
                break;
            case YutSet.BACKDO:
                resultName = "Back Do";
                resultColor = "#A000A0";
                break;
            default:
                resultName = "Unknown";
                resultColor = "#000000";
        }
        
        // Set the result label with appropriate color
        resultLabel.setText("<html><span style='color:" + resultColor + ";'>" + result + " - " + resultName + "</span></html>");
        
        // Call updateAfterThrow to properly handle button state
        updateAfterThrow(result);
    }
    
    /**
     * Resets the sticks to their initial state.
     */
    public void reset() {
        resetSticks();
        resultLabel.setText("Ready!");
        resultLabel.setForeground(new Color(139, 69, 19));
        throwButton.setEnabled(true);
        repaint();
    }
    
    /**
     * Resets the sticks to their initial state.
     */
    private void resetSticks() {
        int centerX = PANEL_WIDTH / 2 - STICK_LENGTH / 2;
        int startY = 80;
        int spacing = STICK_WIDTH + STICK_SPACING;
        
        for (int i = 0; i < 4; i++) {
            stickSides[i] = true; // All front sides initially
            stickRotations[i] = 0;
            stickPositionsX[i] = centerX;
            stickPositionsY[i] = startY + i * spacing;
        }
        repaint();
    }
    
    /**
     * Updates the UI after a throw is completed.
     * 
     * @param result The throw result
     */
    public void updateAfterThrow(int result) {
        // Get roll name
        String resultName = YutSet.getRollName(result);
        
        // Update button state based on roll result
        if (result == YutSet.YUT || result == YutSet.MO) {
            // For YUT or MO, allow another throw
            resultLabel.setText("<html><span style='color:#FF0000;'>" + 
                             resultName + " - You can throw again!</span></html>");
            throwButton.setEnabled(true);
            highlightThrowButton();
        } else if (result == YutSet.BACKDO) {
            // Special handling for BackDo
            resultLabel.setText("<html><span style='color:#A000A0;'>백도 (BackDo) - Move Back One Step</span><br>" +
                             "<span style='color:#000000;'>Select a piece to move</span></html>");
            throwButton.setEnabled(false);
        } else {
            // For normal results (DO, GAE, GEOL), disable throw button
            resultLabel.setText("<html>" + resultName + " - Select a piece to move</html>");
            throwButton.setEnabled(false);
        }
        
        // Check if there are available roll results to process
        if (!game.getAvailableRolls().isEmpty()) {
            resultLabel.setText("Select a piece to move");
        }
    }
    
    /**
     * Sets whether the throw button is enabled.
     */
    public void setThrowEnabled(boolean enabled) {
        if (throwButton != null) {
            throwButton.setEnabled(enabled);
            throwButton.setBackground(enabled ? new Color(135, 206, 235) : Color.GRAY);
        }
    }
    
    /**
     * Highlights the throw button to indicate it should be clicked.
     */
    public void highlightThrowButton() {
        // Create a pulsing animation for the button
        javax.swing.Timer pulseTimer = new javax.swing.Timer(350, new ActionListener() {
            private int pulseCount = 0;
            private final Color originalColor = throwButton.getBackground();
            private final Color pulseColor = new Color(255, 200, 100);
            
            @Override
            public void actionPerformed(ActionEvent e) {
                if (pulseCount % 2 == 0) {
                    throwButton.setBackground(pulseColor);
                    throwButton.setFont(new Font("SansSerif", Font.BOLD, 18)); // 放大字体
                } else {
                    throwButton.setBackground(originalColor);
                    throwButton.setFont(new Font("SansSerif", Font.BOLD, 16)); // 恢复字体
                }
                
                pulseCount++;
                if (pulseCount >= 10 || !throwButton.isEnabled()) { // 增加闪烁次数
                    throwButton.setBackground(originalColor);
                    throwButton.setFont(new Font("SansSerif", Font.BOLD, 16)); // 恢复字体
                    ((javax.swing.Timer)e.getSource()).stop();
                }
            }
        });
        
        pulseTimer.setRepeats(true);
        pulseTimer.start();
    }
    
    /**
     * Arrange sticks neatly in their final positions after animation
     */
    private void arrangeSticks() {
        int centerX = PANEL_WIDTH / 2 - STICK_LENGTH / 2;
        int startY = 80;
        int spacing = STICK_WIDTH + STICK_SPACING;
        
        // Calculate positions for sticks to be neatly arranged
        for (int i = 0; i < 4; i++) {
            stickPositionsX[i] = centerX;
            stickPositionsY[i] = startY + i * spacing;
            stickRotations[i] = 0; // Reset rotation
        }
    }
    
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        
        // Draw traditional mat background
        drawTradMat(g2d);
        
        // Draw title at the top
        g2d.setColor(new Color(100, 60, 20));
        g2d.setFont(new Font("SansSerif", Font.BOLD, 20));
        String title = "Yut Sticks";
        FontMetrics fm = g2d.getFontMetrics();
        g2d.drawString(title, (getWidth() - fm.stringWidth(title))/2, 30);
        
        // Draw yut sticks
        drawYutSticks(g2d);
    }
    
    /**
     * Draws traditional mat background with a more authentic appearance.
     */
    private void drawTradMat(Graphics2D g2d) {
        // Set up quality rendering
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
        
        // Draw the mat background with wooden texture feel
        int width = getWidth();
        int height = getHeight();
        
        // Create a base wood pattern gradient
        GradientPaint woodGrain = new GradientPaint(
            0, 0, new Color(210, 180, 140),
            width, height, new Color(180, 150, 110)
        );
        g2d.setPaint(woodGrain);
        g2d.fillRect(0, 0, width, height);
        
        // Add subtle texture lines
        g2d.setColor(new Color(160, 120, 80, 30));
        g2d.setStroke(new BasicStroke(1.0f));
        
        // Horizontal grain lines
        int lineSpacing = 4;
        for (int y = 0; y < height; y += lineSpacing) {
            int xVariation = new Random(y * 1000).nextInt(3);
            g2d.drawLine(0, y, width, y + xVariation);
        }
        
        // Add a decorative border
        g2d.setColor(new Color(139, 69, 19, 120));
        g2d.setStroke(new BasicStroke(2f));
        g2d.drawRect(5, 5, width - 10, height - 10);
        
        // Add a subtle inner shadow
        g2d.setColor(new Color(0, 0, 0, 20));
        g2d.drawRect(8, 8, width - 16, height - 16);
    }
    
    /**
     * Draws the yut sticks in their current state.
     */
    private void drawYutSticks(Graphics2D g2d) {
        int stickAreaX = 20;
        int stickAreaY = 60;
        int stickAreaWidth = PANEL_WIDTH - 40;
        int stickAreaHeight = 200;
        
        // Draw a subtle background for the stick area
        g2d.setColor(new Color(230, 220, 200, 100));
        g2d.fillRoundRect(stickAreaX, stickAreaY, stickAreaWidth, stickAreaHeight, 15, 15);
        g2d.setColor(new Color(160, 120, 80, 120));
        g2d.drawRoundRect(stickAreaX, stickAreaY, stickAreaWidth, stickAreaHeight, 15, 15);
        
        if (animating) {
            // During animation, draw each stick with its current rotation and position
            for (int i = 0; i < 4; i++) {
                g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                
                // Save current transform
                AffineTransform oldTransform = g2d.getTransform();
                
                // Move to stick position and apply rotation
                g2d.translate(stickPositionsX[i] + STICK_LENGTH/2, stickPositionsY[i] + STICK_WIDTH/2);
                g2d.rotate(Math.toRadians(stickRotations[i]));
                
                // Draw stick based on animation phase
                if (animationStep < TOTAL_ANIMATION_STEPS * 0.7) {
                    // During spinning phase, randomly show front or back
                    boolean showFront = (stickRotations[i] % 180 < 90);
                    drawYutStick(g2d, -STICK_LENGTH/2, -STICK_WIDTH/2, showFront);
                } else {
                    // After settling, show the determined side
                    drawYutStick(g2d, -STICK_LENGTH/2, -STICK_WIDTH/2, stickSides[i]);
                }
                
                // Restore transform
                g2d.setTransform(oldTransform);
            }
        } else {
            // When not animating, draw sticks in neat positions
            int centerX = stickAreaX + stickAreaWidth / 2 - STICK_LENGTH / 2;
            int startY = stickAreaY + 20;
            int spacing = STICK_WIDTH + STICK_SPACING;
            
            for (int i = 0; i < 4; i++) {
                drawYutStick(g2d, centerX, startY + i * spacing, stickSides[i]);
                
                // Draw the red dot on front side for better visibility
                if (stickSides[i]) {
                    g2d.setColor(new Color(180, 30, 30));
                    int dotX = centerX + STICK_LENGTH/2;
                    int dotY = startY + i * spacing + STICK_WIDTH/2;
                    g2d.fillOval(dotX - 5, dotY - 5, 10, 10);
                }
            }
        }
    }
    
    /**
     * Draws a single yut stick at the specified position.
     * 
     * @param g2d The graphics context
     * @param x The x position
     * @param y The y position
     * @param isFront Whether to show the front (flat) side or back (rounded) side
     */
    private void drawYutStick(Graphics2D g2d, int x, int y, boolean isFront) {
        // Enable antialiasing
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        
        if (isFront) {
            // Draw flat (front) side
            g2d.setColor(STICK_FRONT_COLOR);
            g2d.fillRect(x, y, STICK_LENGTH, STICK_WIDTH);
            
            // Draw wood grain on the front side
            drawWoodGrain(g2d, x, y, STICK_LENGTH, STICK_WIDTH, true);
            
            // Draw the edges of the stick
            g2d.setColor(STICK_EDGE_COLOR);
            g2d.setStroke(new BasicStroke(1.0f));
            g2d.drawRect(x, y, STICK_LENGTH, STICK_WIDTH);
        } else {
            // Draw rounded (back) side
            g2d.setColor(STICK_BACK_COLOR);
            
            // Create a rounded rectangle for the back side
            RoundRectangle2D roundedRect = new RoundRectangle2D.Float(
                x, y, STICK_LENGTH, STICK_WIDTH, STICK_CURVE * 2, STICK_WIDTH
            );
            g2d.fill(roundedRect);
            
            // Draw wood grain on the back side
            drawWoodGrain(g2d, x, y, STICK_LENGTH, STICK_WIDTH, false);
            
            // Draw the edges
            g2d.setColor(STICK_EDGE_COLOR.darker());
            g2d.setStroke(new BasicStroke(1.0f));
            g2d.draw(roundedRect);
            
            // Add a highlight to show the curved surface
            g2d.setColor(new Color(255, 255, 255, 40));
            g2d.setStroke(new BasicStroke(2.0f));
            g2d.drawLine(x + 10, y + 3, x + STICK_LENGTH - 10, y + 3);
        }
    }
    
    /**
     * Draws wood grain texture on the sticks.
     * 
     * @param g2d The Graphics2D context
     * @param x The x-coordinate
     * @param y The y-coordinate
     * @param width The width of the stick
     * @param height The height of the stick
     * @param isFront Whether it's the front side
     */
    private void drawWoodGrain(Graphics2D g2d, int x, int y, int width, int height, boolean isFront) {
        // Save current color and stroke
        Color originalColor = g2d.getColor();
        Stroke originalStroke = g2d.getStroke();
        
        // Set the color for the grain lines
        if (isFront) {
            g2d.setColor(new Color(139, 69, 19, 30)); // Light brown for front
        } else {
            g2d.setColor(new Color(255, 255, 255, 15)); // Very light for back
        }
        
        // Draw grain lines
        g2d.setStroke(new BasicStroke(1));
        
        Random random = new Random(x * y);  // Consistent random pattern
        
        for (int i = 0; i < 10; i++) {
            int grainX = x + random.nextInt(width);
            int grainY1 = y + 5;
            int grainY2 = y + height - 5;
            
            // Curve the grain line slightly
            Path2D.Double path = new Path2D.Double();
            path.moveTo(grainX, grainY1);
            
            int controlX1 = grainX + (random.nextInt(10) - 5);
            int controlY1 = grainY1 + (height / 3);
            int controlX2 = grainX + (random.nextInt(10) - 5);
            int controlY2 = grainY1 + (2 * height / 3);
            
            path.curveTo(
                controlX1, controlY1,
                controlX2, controlY2,
                grainX + (random.nextInt(6) - 3), grainY2
            );
            
            g2d.draw(path);
        }
        
        // Restore original settings
        g2d.setColor(originalColor);
        g2d.setStroke(originalStroke);
    }
    
    /**
     * Updates the result label with a custom message.
     * 
     * @param message The message to display
     */
    public void updateMessage(String message) {
        if (resultLabel != null) {
            resultLabel.setText(message);
        }
    }

    /**
     * Sets whether the panel is enabled.
     */
    @Override
    public void setEnabled(boolean enabled) {
        super.setEnabled(enabled);
        setThrowEnabled(enabled);
    }
} 